using Unity.Mathematics;
namespace Geometry
{

    public class Rectangle
    {
        /**
         * @brief The minimum x-coordinate.
         */
       public double minimumX;

        /**
         * @brief The minimum y-coordinate.
         */
       public double minimumY;

        /**
         * @brief The maximum x-coordinate.
         */
       public double maximumX;

        /**
         * @brief The maximum y-coordinate.
         */
      public  double maximumY;

        /**
    * @brief Creates a new instance with all coordinate values set to 0.0.
    *
    * @param minimumX_ The minimum x-coordinate.
    * @param minimumY_ The minimum y-coordinate.
    * @param maximumX_ The maximum x-coordinate.
    * @param maximumY_ The maximum y-coordinate.
    */
      public  Rectangle()
        {
            minimumX = 0.0;
            minimumY = 0.0;
            maximumX = 0.0;
            maximumY = 0.0;
        }

        /**
         * @brief Creates a new instance.
         *
         * Creates a new rectangle from the given coordinates. This implicitly
         * assumes that the given coordinates form a valid rectangle, meaning
         * that `minimumX <= maximumX` and `minimumY <= maximumY`.
         *
         * @param minimumX_ The minimum x-coordinate.
         * @param minimumY_ The minimum y-coordinate.
         * @param maximumX_ The maximum x-coordinate.
         * @param maximumY_ The maximum y-coordinate.
         */
        public Rectangle(
            double minimumX_,
            double minimumY_,
            double maximumX_,
            double maximumY_)
        {
            minimumX = minimumX_;
            minimumY = minimumY_;
            maximumX = maximumX_;
            maximumY = maximumY_;

        }

        /**
         * @brief Checks whether this rectangle contains the given position.
         *
         * This means that the `x`- and `y` coordinates of the given position
         * are not smaller than the minimum and not larger than the maximum
         * coordinates of this rectangle.
         *
         * @param position The position.
         * @returns Whether this rectangle contains the given position.
         */
       public bool contains(double2 position)
        {
            return position.x >= this.minimumX && position.y >= this.minimumY &&
                     position.x <= this.maximumX && position.y <= this.maximumY;
        }

        /**
         * @brief Checks whether this rectangle overlaps the given rectangle.
         *
         * This means that this rectangle and the given rectangle have
         * a non-empty intersection. If either of the rectangles is empty,
         * then this will always return `false`.
         *
         * @param other The other rectangle.
         * @returns Whether this rectangle overlaps the given rectangle.
         */
        bool overlaps(Rectangle other)
        {
            double left = math.max(this.minimumX, other.minimumX);
            double bottom = math.max(this.minimumY, other.minimumY);
            double right = math.min(this.maximumX, other.maximumX);
            double top = math.min(this.maximumY, other.maximumY);
            return bottom < top && left < right;
        }

        /**
         * @brief Checks whether this rectangle fully contains the given rectangle.
         *
         * This means that this rectangle contains all four corner points
         * of the given rectangle, as defined in {@link Rectangle::contains}.
         *
         * @param other The other rectangle.
         * @returns Whether this rectangle fully contains the given rectangle.
         */
        public bool fullyContains(Rectangle other)
        {
            return (
                 other.minimumX >= this.minimumX && other.maximumX <= this.maximumX &&
                 other.minimumY >= this.minimumY && other.maximumY <= this.maximumY);
        }


        /**
         * @brief Computes the signed distance from a position to the edge of the
         * rectangle.
         *
         * If the position is inside the rectangle, the distance is negative. If it is
         * outside the rectangle, it is positive.
         *
         * @param position The position.
         * @return The signed distance.
         */
        public double computeSignedDistance(double2 position)
        {
            double2 bottomLeftDistance = new double2(minimumX, minimumY) - position;
            double2 topRightDistance = position - new double2(maximumX, maximumY);
            double2 maxDistance = math.max(bottomLeftDistance, topRightDistance);

            if (maxDistance.x <= 0.0 && maxDistance.y <= 0.0)
            {
                // Inside, report closest edge.
                return math.max(maxDistance.x, maxDistance.y);
            }
            if (maxDistance.x > 0.0 && maxDistance.y > 0.0)
            {
                // Outside in both directions, closest point is a corner
                return math.length(maxDistance);
            }
            // Outside in one direction, report the distance in that direction.
            return math.max(maxDistance.x, maxDistance.y);
        }

        /**
         * @brief Returns a point at the lower left of this rectangle.
         *
         * This is the point that consists of the minimum x- and y-coordinate.
         *
         * @returns The lower left point.
         */
        public double2 getLowerLeft()
        {
            return new double2(this.minimumX, this.minimumY);
        }

        /**
         * @brief Returns a point at the lower right of this rectangle.
         *
         * This is the point that consists of the maximum x- and minimum y-coordinate.
         *
         * @returns The lower right point.
         */
        public double2 getLowerRight()
        {
            return new double2(this.maximumX, this.minimumY);
        }

        /**
         * @brief Returns a point at the upper left of this rectangle.
         *
         * This is the point that consists of the minimum x- and maximum y-coordinate.
         *
         * @returns The upper left point.
         */
        public double2 getUpperLeft()
        {
            return new double2(this.minimumX, this.maximumY);
        }

        /**
         * @brief Returns a point at the upper right of this rectangle.
         *
         * This is the point that consists of the maximum x- and y-coordinate.
         *
         * @returns The upper right point.
         */
        public double2 getUpperRight()
        {
            return new double2(this.maximumX, this.maximumY);
        }

        /**
         * @brief Returns a point at the center of this rectangle.
         *
         * @returns The center point.
         */
        public double2 getCenter()
        {
            return new double2(
                (this.minimumX + this.maximumX) * 0.5,
                (this.minimumY + this.maximumY) * 0.5);
        }

        /**
         * @brief Computes the width of this rectangle.
         *
         * @returns The width.
         */
        public double computeWidth()
        {
            return this.maximumX - this.minimumX;
        }

        /**
         * @brief Computes the height of this rectangle.
         *
         * @returns The height.
         */
        public double computeHeight()
        {
            return this.maximumY - this.minimumY;
        }

        /**
         * Computes the intersection of this rectangle with another.
         *
         * @param other The other rectangle to intersect with this one.
         * @returns The intersection rectangle, or `std::nullopt` if there is no
         * intersection.
         */
        public Rectangle
            computeIntersection(Rectangle other)
        {
            double left = math.max(this.minimumX, other.minimumX);
            double bottom = math.max(this.minimumY, other.minimumY);
            double right = math.min(this.maximumX, other.maximumX);
            double top = math.min(this.maximumY, other.maximumY);

            if (bottom >= top || left >= right)
            {
                return null;
            }

            return new Rectangle(left, bottom, right, top);
        }

        /**
         * @brief Computes the union of this rectangle with another.
         *
         * @param other The other rectangle to union with this one.
         * @return The union rectangle, which fully contains both rectangles.
         */
        public Rectangle computeUnion(Rectangle other)
        {
            return new Rectangle(
                 math.min(this.minimumX, other.minimumX),
                 math.min(this.minimumY, other.minimumY),
                 math.max(this.maximumX, other.maximumX),
                 math.max(this.maximumY, other.maximumY));
        }

                public static implicit operator bool(Rectangle self)
        {
            return self == null ? false : true;
        }
    }
}